package interpreter;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import composite.ObjectGroup;
import composite.ObjectItem;

/**
 * Database of shapes interpreted from the XML
 * It is singleton, there is no need to parse it more than once.
 */
public class ShapeBase {
	static private ShapeBase instance;
	
	/** List of generated shapes, there are ObjectGroups from composite pattern */
	private List<ObjectGroup> shape_list  = new ArrayList<ObjectGroup>();

	/** Get the instance of singleton */
	public static ShapeBase getInstance(){
        // If there is no object already, create a new one
        if (instance == null)
        {
            instance = new ShapeBase();
        }
        return instance;
	}
	
	/** Private constructor */
	private ShapeBase() {
		//Show file chooser dialog
		JFrame parent = new JFrame();
		JFileChooser fc = new JFileChooser();
		fc.showDialog(parent,"Choose a XML file with shapes.");
		File file = fc.getSelectedFile();
		String filePath;
		filePath = file.getPath();
		
		// Try to parse the XML file
		try {
	        System.out.println("XML parsing started.");
			parseXML(filePath);
			System.out.println("XML parsing ended.");
		} catch (Exception e) {
			e.printStackTrace();
		}	
	}
	
	/** Interprets the XML file into shape_list */
	private void parseXML(String filePath) throws Exception{
		FileInputStream f = new FileInputStream(filePath);
		
	    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
	    DocumentBuilder domBuilder = domFactory.newDocumentBuilder();	    	   
		Document doc = domBuilder.parse(f);
		NodeList shapes = doc.getElementsByTagName("shape");
				
		// Shapes
	    for (int i = 0; i < shapes.getLength(); i++) {
	        Element tmp_node = (Element)shapes.item(i);
	        
	        String name = tmp_node.getAttribute("name");
	        ObjectGroup currentShape = new ObjectGroup(name);
	        
	        System.out.println("New shape found: " + name);
	        //Get lines
        	NodeList nList = tmp_node.getElementsByTagName("line");
    	    for (int temp = 0; temp < nList.getLength(); temp++) {   	   	 
    		       Node nNode = nList.item(temp);
    		       if (nNode.getNodeType() == Node.ELEMENT_NODE) {	    		 
    		          Element eElement = (Element) nNode;
    		 
    		          PrimitiveLine tmpLine = new PrimitiveLine(getTagValue("x1",eElement),
    		        		  									getTagValue("y1",eElement),
    		        		  									getTagValue("x2",eElement),
    		        		  									getTagValue("y2",eElement) );
    		          currentShape.addObjectItem(tmpLine);
    		        }
	        }//lines
	        //Get arches
        	NodeList nList2 = tmp_node.getElementsByTagName("arch");
    	    for (int temp = 0; temp < nList2.getLength(); temp++) {   	   	 
    		       Node nNode = nList2.item(temp);
    		       if (nNode.getNodeType() == Node.ELEMENT_NODE) {	    		 
    		          Element eElement = (Element) nNode;
    		 
    		          PrimitiveArch tmpArch = new PrimitiveArch(getTagValue("startX",eElement),
    		        		  									getTagValue("startY",eElement),
    		        		  									getTagValue("width",eElement),
    		        		  									getTagValue("high",eElement),
    		        		  									getTagValue("startAngle",eElement),
    		        		  									getTagValue("extendAngle",eElement) );
    		          currentShape.addObjectItem(tmpArch);
    		        }
	        }//arches
    	  
    	    shape_list.add(currentShape);
	    }//shapes 
	}
	
	private int getTagValue(String sTag, Element eElement){
	    NodeList nlList= eElement.getElementsByTagName(sTag).item(0).getChildNodes();
	    Node nValue = (Node) nlList.item(0); 
	 
	    return Integer.parseInt(nValue.getNodeValue());    
	 }
	
	public List<ObjectGroup> get_shape_list() {
		return shape_list;
	}
	
	/** Get shape by name */
	public ObjectItem get_shape(String name){
		// Search for given shape name
		for (int i = 0; i < shape_list.size(); i++) {
			String tmpName = shape_list.get(i).getName();
			if( tmpName.equals(name)){
				ObjectItem tmpShape = shape_list.get(i).clone();
				return tmpShape;
			}
		}
		// If there was no match
		return null;
	}
}
